from datetime import datetime
import os
import platform
import ntpath
import requests
from astropy.io import fits
from loguru import logger
from PIL import Image, ImageDraw, ImageFont


class ImageProcessor:
    def __init__(self, target_name, filter_name, base_url="http://192.168.16.206:56000/V20240815/"):
        """
        初始化图像处理类。

        参数：
        - target_name (str): 目标对象的名称。
        - filter_name (str): 使用的滤光片名称。
        - base_url (str): 图片下载的基本 URL。默认为一个本地地址。
        """
        self.target_name = target_name
        self.filter_name = filter_name
        self.base_url = base_url
        self.maindir = "."  # 主目录
        self.imgdir = os.path.join(self.maindir, "images", self.target_name)
        self.cal_dir = os.path.join(self.imgdir, "cal")  # 保存下载图片的目录
        self.img_list_name = os.path.join(self.imgdir, f"images_{self.filter_name}.list")
        self.downloaded_images = []  # 下载后的图片路径列表

        # 创建保存图片的子目录
        os.makedirs(self.cal_dir, exist_ok=True)

        # 定义字体路径（根据操作系统判断）
        if platform.system() == "Windows":
            self.default_font_path = "C:\\Windows\\Fonts\\Arial.ttf"
        elif platform.system() == "Darwin":  # macOS
            self.default_font_path = "/Library/Fonts/Arial.ttf"
        else:  # Linux 或其他系统
            self.default_font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"

    def format_date(self, datetime_str):
        """
        将日期时间字符串格式化为 YYYYMMDD 格式。

        参数：
        - datetime_str (str): 原始日期时间字符串，格式为 "YYYY-MM-DDTHH:MM:SS"

        返回：
        - str: 格式化后的日期字符串，例如 "20230815"
        """
        try:
            dt = datetime.strptime(datetime_str, "%Y-%m-%dT%H:%M:%S")
            return dt.strftime("%Y%m%d")
        except ValueError as e:
            logger.error(f"日期格式错误: {e} | 输入: {datetime_str}")
            return None

    def download_image(self, url, save_path):
        """
        从指定的 URL 下载图片并保存到指定路径。

        参数：
        - url (str): 图片的下载链接。
        - save_path (str): 图片的保存路径。
        """
        try:
            response = requests.get(url, timeout=30)  # 设置超时时间为30秒
            response.raise_for_status()  # 如果响应状态码不是200，将引发HTTPError
            with open(save_path, 'wb') as f:
                f.write(response.content)
            logger.info(f"成功下载: {url} -> {save_path}")
            return True
        except requests.exceptions.RequestException as e:
            logger.error(f"下载失败: {e} | URL: {url}")
        return False

    def add_text_to_image(self, image_path, text, output_path, position=(10, 10),
                          font_size=20, color=(255, 255, 255)):
        """
        在图像上添加文本标签并保存。

        参数：
        - image_path (str): 原始图像的路径。
        - text (str): 要添加的文本内容。
        - output_path (str): 添加文本后图像的保存路径。
        - position (tuple): 文本在图像上的位置，默认左上角 (10, 10)。
        - font_size (int): 字体大小，默认20。
        - color (tuple): 文本颜色，默认为白色 (255, 255, 255)。
        """
        try:
            with Image.open(image_path) as img:
                draw = ImageDraw.Draw(img)
                font = ImageFont.truetype(self.default_font_path, font_size) if os.path.isfile(self.default_font_path) else ImageFont.load_default()
                draw.text(position, text, font=font, fill=color)
                img.save(output_path)
                logger.info(f"已添加文本 '{text}' 到图像: {output_path}")
        except Exception as e:
            logger.error(f"在图像 {image_path} 上添加文本 '{text}' 失败 - 错误: {e}")

    def images_to_pdf(self, image_paths, output_pdf_path):
        """
        将指定的有序图片列表拼接成一个 PDF 文件。

        参数：
        - image_paths (list of str): 图片文件路径的有序列表。
        - output_pdf_path (str): 生成的 PDF 文件的保存路径。
        """
        try:
            if not image_paths:
                logger.error("传入的图片列表为空，没有图片用于生成 PDF。")
                return

            images = []
            for img_path in image_paths:
                try:
                    with Image.open(img_path) as img:
                        if img.mode in ('RGBA', 'P'):
                            img = img.convert('RGB')
                        images.append(img.copy())
                    logger.info(f"已加载图片用于 PDF: {img_path}")
                except Exception as e:
                    logger.error(f"无法打开图片 {img_path} - 错误: {e}")

            if not images:
                logger.error("没有有效的图片可用于生成 PDF。")
                return

            # 保存为 PDF
            first_image, *rest_images = images
            first_image.save(
                output_pdf_path,
                "PDF",
                resolution=100.0,
                save_all=True,
                append_images=rest_images
            )
            logger.info(f"成功生成 PDF: {output_pdf_path}")

        except Exception as e:
            logger.error(f"生成 PDF 时出错: {e}")

    def process_images(self):
        """
        主处理函数：下载图片，添加文本，生成 PDF。
        """
        if not os.path.isfile(self.img_list_name):
            logger.error(f"图像列表文件不存在: {self.img_list_name}")
            return

        with open(self.img_list_name, "r") as f:
            img_list = f.read().splitlines()

        if not img_list:
            logger.warning(f"图像列表文件为空: {self.img_list_name}")
            return

        for im_ in img_list:
            temp_ = os.path.join(self.imgdir, im_)

            try:
                header = fits.getheader(temp_)
            except Exception as e:
                logger.error(f"无法读取 FITS 头信息: {temp_} - 错误: {e}")
                continue

            date_ = header.get("DATE")
            filter_ = header.get("FILTER")
            object_ = header.get("OBJECT")

            if not date_ or not filter_ or not object_:
                logger.warning(f"缺少必要的头信息: {temp_}")
                continue

            date_str = self.format_date(date_)
            if not date_str:
                logger.warning(f"无法格式化日期: {date_} - 文件: {temp_}")
                continue

            base_url = (
                f"{self.base_url}{date_str}/{date_str}_{im_[:2]}_{object_}_{filter_}/"
                f"CalibrationResidual_{im_[:-5]}_sexcat_CalSource_CalMag.png"
            )
            logger.info(f"生成的 URL: {base_url}")

            image_filename = ntpath.basename(base_url)
            save_path = os.path.join(self.cal_dir, image_filename)

            if self.download_image(base_url, save_path):
                labeled_image_path = os.path.join(self.cal_dir, f"labeled_{image_filename}")

                # 添加文件名文本到图像
                self.add_text_to_image(
                    image_path=save_path,
                    text=image_filename.replace("CalibrationResidual_", ""),
                    output_path=labeled_image_path,
                    position=(700, 10),
                    font_size=20,
                    color=(0, 0, 0)
                )

                self.downloaded_images.append(labeled_image_path)
            else:
                logger.warning(f"跳过未能下载的图片: {save_path}")

        if not self.downloaded_images:
            logger.error("没有任何图片被成功下载，无法生成 PDF。")
            return

        output_pdf_path = os.path.join(self.imgdir, f"{self.target_name}_{self.filter_name}_CalibrationResidual.pdf")
        self.images_to_pdf(self.downloaded_images, output_pdf_path)


def main():
    target_name = "sn2025baq"
    filter_name = "v"

    processor = ImageProcessor(target_name, filter_name)
    processor.process_images()


if __name__ == "__main__":
    main()
